package conv

import (
	"errors"
	"reflect"
)

//目的：1读取结构体各属性，并进行遍历操作

func newVal(s reflect.StructField, v reflect.Value, structName string) *Val {
	o := new(Val)
	o.S = s
	o.V = v
	o.keyName = s.Name
	o.structName = structName
	return o
}

type Val struct {
	S          reflect.StructField
	V          reflect.Value
	keyName    string
	structName string
}

//字段类型
func (this *Val) Type() string {
	return this.S.Type.String()
}

//属性名称
func (this *Val) Name() string {
	return this.keyName
}

//字段值
func (this *Val) Value() interface{} {
	return this.V.Interface()
}

//结构体名称
func (this *Val) StructName() string {
	return this.structName
}

//获取字段tag
func (this *Val) Tag(k string) string {
	return this.S.Tag.Get(k)
}

//给value赋任意值
//Field =int    Value=string
//Field =string Value=int
//Field =int	Value=int
func (this *Val) Set(x interface{}) error {
	v := reflect.ValueOf(x)
	if !this.V.CanSet() {
		return errors.New("can't set.")
	}
	//如果两者是同一类型
	if v.Type().Kind() == this.V.Kind() {
		this.V.Set(v)
		return nil
	}
	return Value(x, this.V)
}

//遍历结构体，obj必须传入指针类型，且为结构体
func EachStruct(obj interface{}, call func(*Val)) {
	ref := reflect.ValueOf(obj)
	if ref.Kind() == reflect.Ptr && ref.Elem().Kind() == reflect.Struct {
		ele := ref.Elem()
		nums := ele.NumField()
		typ := ele.Type()
		structName := ref.Elem().Type().Name()
		for i := 0; i < nums; i++ {
			call(newVal(typ.Field(i), ele.Field(i), structName))
		}
	}
}
